﻿using Furion.DataEncryption;
using GMS.NET.Dto.System.Auth.Shared;
using GMS.NET.Encrypt;
using Furion.JsonSerialization;
using GMS.NET.Const;
using GMS.NET.Core.Entitys.System;
using Furion.FriendlyException;
using GMS.NET.Core.Provider.CacheProvider;
using Furion.EventBus;
using GMS.NET.Core.Tools.Email;
using GMS.NET.Dto.System.Auth.Input;
using GMS.NET.Application.Service.System.Auth;

namespace GMS.NET.Application.Service.Auth
{
    [AllowAnonymous]
    [DynamicApiController]
    public class AuthService : DbManger, IAuthService
    {
        private readonly ICachingService cache = App.GetService<ICachingProvider>().GetCache();
        private readonly IEventPublisher events = App.GetService<IEventPublisher>();
        /// <summary>
        /// 授权登陆
        /// </summary>
        /// <returns></returns>
        public async Task LoginAuth([FromBody] LoginAuth loginAuth)
        {
            //获取私钥
            var privateKey = App.Configuration.GetSection(EncryptConst.PrivateKey).Value ?? "";
            //解密并反序列化用户数据
            var logUsr = JSON.Deserialize<LoginBasic>(RSA.Decrypt(loginAuth.Ciphertext!, privateKey));
            //获取用户信息
            AuthUser User;
            string UserNotexHint;
            switch (logUsr.Mode)
            {
                case LoginType.Default:
                    //解密密码并使用SHA加密
                    var passWord = SHA.Hash512(RSA.Decrypt(logUsr.Password!, privateKey));
                    //根据账号密码对比数据库
                    User = await MasterDb.Queryable<GMSNet_User>()
                       .LeftJoin<GMSNet_Customer>((x, y) => x.User_CusId == y.Id)
                       .LeftJoin<GMSNet_Role>((x, y, z) => x.User_RoleId == z.Id)
                       .Where((x) => x.User_Account == logUsr.Account
                       && x.User_PassWord == passWord)
                       .Select((x, y, z) => new AuthUser
                       {
                           IsAuth = SqlFunc.Subqueryable<GMSNet_Authority>().Where(a => a.Auth_RoleId == x.User_RoleId).Any()
                       }, true).FirstAsync();
                    UserNotexHint = "账号或密码错误";
                    break;
                case LoginType.Email:
                    //根据邮箱对比数据库
                    User = await MasterDb.Queryable<GMSNet_User>()
                       .LeftJoin<GMSNet_Customer>((x, y) => x.User_CusId == y.Id)
                       .LeftJoin<GMSNet_Role>((x, y, z) => x.User_RoleId == z.Id)
                       .Where((x) => x.User_Email == logUsr.Account)
                       .Select((x, y, z) => new AuthUser
                       {
                           IsAuth = SqlFunc.Subqueryable<GMSNet_Authority>().Where(a => a.Auth_RoleId == x.User_RoleId).Any()
                       }, true).FirstAsync();
                    UserNotexHint = "邮箱错误或不存在";
                    break;
                case LoginType.Phone:
                    //根据手机对比数据库
                    User = await MasterDb.Queryable<GMSNet_User>()
                       .LeftJoin<GMSNet_Customer>((x, y) => x.User_CusId == y.Id)
                       .LeftJoin<GMSNet_Role>((x, y, z) => x.User_RoleId == z.Id)
                       .Where((x) => x.User_Phone == logUsr.Account)
                       .Select((x, y, z) => new AuthUser
                       {
                           IsAuth = SqlFunc.Subqueryable<GMSNet_Authority>().Where(a => a.Auth_RoleId == x.User_RoleId).Any()
                       }, true).FirstAsync();
                    UserNotexHint = "手机错误或不存在";
                    break;
                default:
                    User = null!;
                    UserNotexHint = "用户错误";
                    break;
            }

            var userAdmin = App.GetOptions<UserAdminOptions>();

            if (User is null)
                throw Oops.Bah(UserNotexHint);
            var IsAdminUser = User.User_RoleId == new Guid(userAdmin.RoleId!)
                && User.User_CusId == new Guid(userAdmin.CustsId!);
            if (IsAdminUser)
                goto useradmin;
            if (User.User_Status == 0)
                throw Oops.Bah("用户已被禁用");
            if (User.User_Type == 2)
                throw Oops.Bah("用户类型在此不可使用");
            if (User.User_RoleId == Guid.Empty)
                throw Oops.Bah("用户未分配角色");
            if (User.User_CusId == Guid.Empty)
                throw Oops.Bah("用户未分配所属客户");
            if (User.Cust_Status == 0 || User.Cust_Status == 2)
                throw Oops.Bah("用户所属客户状态异常");
            if (User.Role_Status == 2)
                throw Oops.Bah("用户所属角色已被禁用");
            if (!User.IsAuth)
                throw Oops.Bah("用户未授权可用资源");

            useradmin:
            int tokenExpmin = 90;
            //生成服务端数据连接信息缓存
            if (!IsAdminUser) await cache.SetAsync(UserClaimConst.CacheConnectString(User.User_Account!), new SaasUserInfo() { CusId = User.User_CusId.ToString(), Connection = User.Cust_Connection }, TimeSpan.FromMinutes(tokenExpmin));

            // 生成客户端token
            var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>()
            {
                { UserClaimConst.UserAdmin, IsAdminUser},
                { UserClaimConst.UserName, User.User_Name!},
                { UserClaimConst.UserId, User.User_Account!},
                { UserClaimConst.CusId, User.User_CusId},
                { UserClaimConst.RoleId, User.User_RoleId},
                { UserClaimConst.CusName, User.Cust_Name!},
            }, tokenExpmin);

            await events.PublishAsync(EventBusConst.LogsWriteBasic, new GMSNet_LOG()
            {
                Id = Guid.NewGuid(),
                LOG_Content = $"{User.User_Account}{SplitCharConst.α}{ApiTool.GetIp()}",
                LOG_LogLevel = LogLevelConst.Login,
                Creationtime = DateTime.Now,
                Creator = User.User_Account
            });

            App.HttpContext.Response.Headers.Add("AccessToken", accessToken);
            App.HttpContext.Response.Headers.Add("TimeLcs", (tokenExpmin * 60 * DateTime.Now.Day).ToString());
        }
        public async Task SendEmailCode([FromBody] LoginAuth loginAuth)
        {
            //获取私钥
            var privateKey = App.Configuration.GetSection(EncryptConst.PrivateKey).Value ?? "";
            //解密并反序列化用户数据
            var logEmail = JSON.Deserialize<SendEmail>(RSA.Decrypt(loginAuth.Ciphertext!, privateKey));

            if (await MasterDb.Queryable<GMSNet_User>()
                .AnyAsync(x => x.User_Email == logEmail.Email))
                EmailTool.MailKitEmail(new()
                {
                    receiverEmails =new() { logEmail.Email! },
                    subject = "GMSNET登陆验证码",
                    body = $"您有一个登陆验证码请及时使用,验证码是{logEmail.EmailCode}"
                });
            else
                throw Oops.Bah("邮箱不存在");
        }
        public Task SendPhoneCode([FromBody] LoginAuth loginAuth)
        {
            throw Oops.Oh("暂未开通手机验证码");
        }
    }
}
